#include "tfcalc.h"
#include <math.h>
#include <leven.h>

tfcalc::tfcalc()
{
}

tfcalc::tfcalc(QList<DocStruct> dStruct)
{
    addDoc(dStruct);
}

void tfcalc::clear()
{
    tf.clear();
}

void tfcalc::addDoc(QList<DocStruct> dStruct)
{
    doc_size = 0;
    QHash< QString, QList<float> >::iterator tfIt;
    QList<DocStruct>::iterator docIt;
    for (docIt = dStruct.begin(); docIt != dStruct.end(); docIt++)
    {
        foreach (QString str, docIt->Text)
        {
            tfIt = tf.find(str);
            if (tfIt == tf.end())
            {
                QList<float> vec;
                for (int i = 0;i < dStruct.count(); i++)
                {
                    vec << 0;
                }
                tf.insert(str, vec);
                tf.find(str).value()[doc_size]++;
            }
            else
            {
                tf.find(str).value()[doc_size]++;
            }
        }
        doc_size++;
    }
    doc_size = doc_size;
}

QHash< QString, QList<float> > tfcalc::calculateTFIDF(QHash<QString, vect> mtd)
{
    float idfc;
    float n;

    QHash<QString, float>::iterator iter;
    QHash< QString, QList<float> >::iterator tfIt;
            for (tfIt = mtd.begin(); tfIt != mtd.end(); tfIt++)
            {
                    n = 0;
                    QList<float>::iterator i;
                    for ( i = tfIt.value().begin(); i != tfIt.value().end(); i++)
                    {
                            if ( *i != 0 )
                            {
                                    n++;
                            }
                    }
                    n = mtd.count()/n;
                    idfc = log(n);
                    iter = idf.find(tfIt.key());
                    if (iter == idf.end())
                    {
                        idf.insert(tfIt.key(),idfc);
                    }
            }
    QHash< QString, QList<float> > tfidf (tf);
    for (tfIt = tfidf.begin(); tfIt != tfidf.end(); tfIt++)
    {
        QList<float>::iterator i;
        for (i = tfIt.value().begin(); i != tfIt.value().end(); i++)
        {
            iter = idf.find(tfIt.key());
            *i *=iter.value();
        }
    }
    return tfidf;
}

unsigned int tfcalc::getDocCount()
{
    return doc_size;
}

QList<vect> tfcalc::calculateDist(QHash<QString, vect> mtd, QString type)
{
    QList<float> distn;
    QList<vect> distance;
    distance.clear();
    for (unsigned int n1 = 0; n1 != doc_size; n1++ )
    {
        for (unsigned int n2 = 0; n2 != doc_size; n2++ )
        {
            if (type == "rbEucl") {distn.push_back(calculateEucl(n1,n2,mtd));}
            if (type == "rbManh") {distn.push_back(calculateManh(n1,n2,mtd));}
            if (type == "rbCheb") {distn.push_back(calculateCheb(n1,n2,mtd));}
        }
        distance.push_back(distn);
        distn.clear();
    }
    distmax = 0;
    for (QList<vect>::iterator ifloat = distance.begin(); ifloat != distance.end(); ifloat++)
            {
                    for (QList<float>::iterator ivfloat = ifloat->begin(); ivfloat != ifloat->end(); ivfloat++)
                    {
                            if ( *ivfloat > distmax )
                            {
                                    distmax = *ivfloat;
                            }
                    }
            }
    return distance;
}

float tfcalc::calculateEucl(unsigned int i1, unsigned int i2,QHash<QString, vect> mtd)
{
    float c = 0;
    for (QHash< QString, QList<float> >::iterator tfIt = mtd.begin(); tfIt != mtd.end(); tfIt++)
    {
        {

        float a = tfIt.value()[i1];
        float b = tfIt.value()[i2];
        c += (a-b)*(a-b);
        }
    }
    return sqrt(c);
}

float tfcalc::calculateManh(unsigned int i1, unsigned int i2,QHash<QString, vect> mtd)
{
    float c = 0;
    for (QHash< QString, QList<float> >::iterator tfIt = mtd.begin(); tfIt != mtd.end(); tfIt++)
    {
        {

        float a = tfIt.value()[i1];
        float b = tfIt.value()[i2];
        c += qAbs(a-b);
        }
    }
    return c;
}

float tfcalc::calculateCheb(unsigned int i1, unsigned int i2,QHash<QString, vect> mtd)
{
    float c = 0;
    for (QHash< QString, QList<float> >::iterator tfIt = mtd.begin(); tfIt != mtd.end(); tfIt++)
    {
        {

        float a = tfIt.value()[i1];
        float b = tfIt.value()[i2];
        if (qAbs(a-b) > c)
        {
            c = qAbs(a-b);
        }
        }
    }
    return c;
}

QList<vect> tfcalc::getDist(QString dist, QString weight)
{
    QHash< QString, QList<float> > _weight;
    if (weight == "rbTF") {_weight = tf;}
    if (weight == "rbTFIDF") {_weight = calculateTFIDF(tf);}
    return calculateDist(_weight,dist);
}

QList<vect> tfcalc::getDist(QString type)
{
    if (type == "rbJac")
    {
        return calculateJaccard();
    }
}

QList<vect> tfcalc::calculateJaccard()
{
    QList<float> jacc;
    QList<vect> jaccard;
    QHash< QString, QList<float> >::iterator it;
    for (unsigned int n1 = 0; n1 != doc_size; n1++)
    {
        for (unsigned int n2 = 0; n2 != doc_size; n2++)
        {
                float a = 0;
                float b = 0;
                float c = 0;
                float Jac = 0;
                for ( it = tf.begin(); it != tf.end(); it++)
                {
                    if ( (it.value()[n1] != 0) && (it.value()[n2] != 0) )
                    {
                        a++;
                    }
                    if ( (it.value()[n1] != 0) && (it.value()[n2] == 0) )
                    {
                        b++;
                    }
                    if ( (it.value()[n1] == 0) && (it.value()[n2] != 0) )
                    {
                        c++;
                    }
                }
                Jac = a/(a+b+c);
                jacc.push_back(Jac);
        }
        jaccard.push_back(jacc);
        jacc.clear();
    }
    return jaccard;
}

//int tfcalc::calculateLeven(QStringList strL1, QStringList strL2)
//{
//    int diff;
//    int m[strL1.length()+1][strL2.length()+1];
//    for (int i = 0; i <= strL1.length(); i++)
//    {
//        *m[i,0] = i;
//    }
//    for (int j = 0; j <= strL2.length(); j++)
//    {
//        *m[0,j] = j;
//    }
//    for (int i = 1; i <= strL1.length(); i++)
//        for (int j = 1; j <= strL2.length(); j++)
//        {
//            diff = (strL1[i - 1] == strL2[j - 1]) ? 0 : 1;
//            *m[i,j] = Min(Min( *m[i-1,j]+1,*m[i,j-1]+1 ),*m[i-1,j-1]+diff );
//        }

//    return *m[strL1.length(),strL2.length()];
//}

QList<vect> tfcalc::calculateLeven(QList<DocStruct> dStruct)
{
    QList<vect> Leven;
    QList<float> Lev;

    Leven.clear();
    for (unsigned int n1 = 0; n1 != doc_size; n1++ )
    {
        for (unsigned int n2 = 0; n2 != doc_size; n2++ )
        {
           // Lev.push_back(calculateLeven( dStruct[n1].Text,  dStruct[n2].Text));
             Lev.push_back(levenshtein_distance( dStruct[n1].Text,  dStruct[n2].Text));
        }
        Leven.push_back(Lev);
        Lev.clear();
    }

    return Leven;
}

QList<vect> tfcalc::calculateShingle(QList<DocStruct> dStruct, int shLength, int hashLength)
{
    QList<vect> Shingle;
    QList<vect> Shingle1;
    QList<float> _Shingle;
    QList<float> _Shingle1;
    QList<QStringList> shingleList;
    QStringList _shingleList;
    //QStringList tempList = dStruct[0].Text;
    QString _shingleStr;
    QList<DocStruct>::iterator it;
    for (it = dStruct.begin(); it != dStruct.end(); it++)
    {
        int length = Min(it->Text.length(),shLength);
        for (int i = 0; i <= it->Text.length() - length; i++)
        {
            _shingleStr = "";
            for (int j = 0; j < length; j++)
            {
                _shingleStr += it->Text[j+i];
            }
            _shingleList.append(md5Hash(_shingleStr));
            //_shingleList.append(_shingleStr);
        }
        _shingleList.sort();
        if (_shingleList.count() > hashLength)
        for (int i = 0; i <= _shingleList.count() - hashLength; i++ ) _shingleList.removeLast();
        shingleList.append(_shingleList);
        _shingleList.clear();
    }

    QList<QStringList>::iterator listIt1;
    QList<QStringList>::iterator listIt2;
    QStringList::iterator strIt1;
    QStringList::iterator strIt2;
    int i = 0;
    for (listIt1 = shingleList.begin(); listIt1 != shingleList.end(); listIt1++)
    {
        for (listIt2 = shingleList.begin(); listIt2 != shingleList.end(); listIt2++)
        {
            i = 0;
            for (strIt1 = listIt1->begin(); strIt1 != listIt1->end(); strIt1++)
            {
                for (strIt2 = listIt2->begin(); strIt2 != listIt2->end(); strIt2++)
                {
                    if ( *strIt1 == *strIt2 )
                    {
                        i++;
                    }
                }
            }
            float ii = i;
//            _Shingle.append(ii/ shingleList.count());
            _Shingle.append(ii);
        }
        Shingle.push_back(_Shingle);
        _Shingle.clear();
    }
//    for (int i = 0; i < Shingle.length(); ++i )
//    {
//        for (int j = 0; j < Shingle.length(); ++j)
//        {
//            if (i != j)
//            {
//                _Shingle1.push_back(Shingle.at(i).at(j));//((Shingle.at(i).at(i) + Shingle.at(j).at(j)) - Shingle.at(i).at(j))
//                                  //    /(Shingle.at(i).at(i) + Shingle.at(j).at(j)));
//            }
//            else
//            {
//                _Shingle1.push_back(Shingle.at(i).at(j));
//            }
//        }
//        Shingle1.push_back(_Shingle1);
//    }

    return Shingle;
}
